package client

import (
	"context"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"github.com/go-pay/gopay/pkg/xlog"
	"github.com/spf13/cast"
	"longmen/server/config/global"
	"longmen/server/pkg/db/mysql/models/models_main"
	pb "longmen/server/pkg/protobuf"
	"net/url"
	"strings"
)

func AliPay(api *models_main.PaymentApi, paymentApply *pb.PaymentApply) (*pb.HsqBusinessResp, error) {
	isProd := global.Config.GetBoolOrDefault("aliPay.isProd", false)
	hsqBusinessResp := &pb.HsqBusinessResp{}
	// 初始化支付宝客户端
	//    appid：应用ID
	//    privateKey：应用私钥，支持PKCS1和PKCS8
	//    isProd：是否是正式环境

	client, err := alipay.NewClient(api.ApiAccount, api.ApiParams, isProd)
	if err != nil {
		xlog.Error(err)
		return nil, err
	}
	// 自定义配置http请求接收返回结果body大小，默认 10MB
	client.SetBodySize(5) // 没有特殊需求，可忽略此配置
	// 打开Debug开关，输出日志，默认关闭
	client.DebugSwitch = gopay.DebugOn

	// 设置支付宝请求 公共参数
	//    注意：具体设置哪些参数，根据不同的方法而不同，此处列举出所有设置参数
	client.SetLocation(alipay.LocationShanghai). // 设置时区，不设置或出错均为默认服务器时间
							SetCharset(alipay.UTF8).  // 设置字符编码，不设置默认 utf-8
							SetSignType(alipay.RSA2). // 设置签名类型，不设置默认 RSA2
							SetReturnUrl(api.ApiHost) // 设置返回URL
	//SetNotifyUrl("https://www.fmm.ink") // 设置异步通知URL
	//SetAppAuthToken() // 设置第三方应用授权

	// 自动同步验签（只支持证书模式）
	// 传入 alipayCertPublicKey_RSA2.crt 内容
	//client.AutoVerifySign([]byte("alipayCertPublicKey_RSA2 bytes"))

	// 公钥证书模式，需要传入证书，以下两种方式二选一
	// 证书路径
	err = client.SetCertSnByPath("secret/appCertPublicKey_2021000121618269.crt", "secret/alipayRootCert.crt", "secret/alipayCertPublicKey_RSA2.crt")
	// 初始化 BodyMap
	bm := make(gopay.BodyMap)
	/*bm.SetBodyMap("business_address", func(bm gopay.BodyMap) {
		bm.Set("city_code", "37100")
		bm.Set("district_code", "371002")
		bm.Set("address", "万塘路18号黄龙时代广场B座")
		bm.Set("province_code", "310000")
	})
	bm.Set("shop_category", "B0001")*/

	/*	Set("subject", "条码支付").
		Set("scene", "bar_code").
		Set("auth_code", "286248566432274952").
		Set("out_trade_no", "GZ201909081743431443").
		Set("total_amount", "0.01")*/
	bm. //Set("subject", "二维码支付").
		//Set("scene", "bar_code").

		Set("subject", "二维码支付").
		Set("total_amount", paymentApply.Price).
		Set("item_carat", paymentApply.ItemCarat).
		Set("out_trade_no", paymentApply.OrderNo).
		Set("user_id", paymentApply.UserId).
		Set("timeout_express", "6m")
	if aliRsp, err1 := client.TradePrecreate(context.Background(), bm); err1 == nil {
		if bizErr, ok := alipay.IsBizError(err1); !ok {
			if bizErr == nil {
				hsqBusinessResp.Extend = cast.ToString(paymentApply.UserId)
				hsqBusinessResp.OrderAmt = cast.ToString(paymentApply.Price)
				hsqBusinessResp.TransNo = paymentApply.OrderNo
				hsqBusinessResp.QrCode = aliRsp.Response.QrCode
				return hsqBusinessResp, nil
			} else {
				fmt.Println(bizErr)
			}
		}
		xlog.Errorf("client.TradePay(%+v),err:%+v", bm, err)
	}
	return nil, err
}

func AliPayCallBack(params string) *pb.PaymentApply {
	// 解析异步通知的参数
	//    req：*http.Request

	//    value：url.Values
	notifyReq, err := alipay.ParseNotifyByURLValues(parseUrlValue(params))
	if err != nil {
		xlog.Error(err)
		return nil
	}
	paymentApply := &pb.PaymentApply{}
	// 支付宝异步通知验签（公钥证书模式）
	if ok, _ := alipay.VerifySignWithCert("secret/alipayCertPublicKey_RSA2.crt", notifyReq); ok {
		// 如果需要，可将 BodyMap 内数据，Unmarshal 到指定结构体指针 ptr type struct
		err = notifyReq.Unmarshal(paymentApply)
		return paymentApply
	}
	//程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）
	return nil
}

func parseUrlValue(val string) url.Values {
	data := url.Values{}

	parameters := strings.Split(val, "&")

	for _, parameter := range parameters {

		parts := strings.Split(parameter, "=")

		data.Add(parts[0], parts[1])

	}
	return data
}
